#include<stdio.h>
#include<stdlib.h>
#include"typedef.h"
#include"getnum.h"
#include<time.h>


int load(tipoJuego *juego, char *nombre);
int save(tipoJuego* juego, char *nombre);
void pideParam(tipoParametros *parametros);
int pideMem(tipoTablero **tablero, tipoParametros parametros);
void llenaTablero(tipoJuego *juego);
int creaLibres(tipoTablero *tablero, tipoPunto **puntos);
void bolitasAleat(tipoJuego *juego);
void agrega_bolita(tipoTablero *tablero, int r, int  i, int j);
void copiaEstruct(tipoPunto *a, tipoPunto * b);
int posibleMov(tipoJuego * juego, tipoPunto origen, tipoPunto destino, int *existe);
int posCamino(tipoTablero * tablero, tipoPunto origen, tipoPunto destino, int *existe);
int pertenMat(tipoTablero * tablero, tipoPunto punto);
int swap(tipoTablero * tablero, tipoPunto origen, tipoPunto destino);
void tomaMov(tipoPunto *origen, tipoPunto *destino);
void actualizaLibresM(tipoTablero * tablero, tipoPunto coordIni, tipoPunto coordFin);
int ceros(tipoTablero * tablero);
int cuentaDiag(tipoTablero * tablero, int color, int i, int j, int orient);
int cuentaVer(tipoTablero * tablero, int color, int i, int j);
int cuentaHor(tipoTablero * tablero, int color, int i, int j);
int elimDiag(tipoTablero * tablero, int i, int j, int * elim, int linea, int color, int orient);
int elimVer(tipoTablero * tablero, int i, int j, int * elim, int linea, int color);
int elimHor(tipoTablero * tablero, int i, int *j, int * elim, int linea, int color);
int posibleElim(tipoJuego * juego, int *elim, int linea, int cantColores);
int pideIn(tipoJuego *juego, int *movida, int *elim, time_t tiempoIni);
int validaIn(tipoJuego * juego, char *s, int *movida, int *elim);
int validMov(tipoParametros param, char *s, int vec[]);
void imprimePuntaje(tipoJuego *juego, int jugador);
void imprimeTablero(tipoJuego *juego);
int juegoNormal(tipoJuego * juego);
void sumaPuntaje(tipoJuego *juego,int eliminados);
int tableroLleno(tipoTablero * tablero);
int CoordValidas(tipoJuego *juego, tipoPunto origen, tipoPunto destino);
void imprMsg(int var);
char * pideNombre(void);
int menu(void);
int randInt(int inicio, int final);
void imprimeFila(tipoTablero *tablero, int i, int j);
void cambiaTurno(tipoJuego * juego);
int guardaUndo(tipoJuego * juego);
int cargoUndo(tipoJuego * juego);
int copiaTablero(tipoTablero *origen, tipoTablero *destino);
void quitTablero(tipoTablero **tablero);
int quit(tipoJuego *juego);
int hayTiempo(tipoJuego * juego, time_t tiempoIni);
void imprimeTiempo(tipoJuego * juego);
int cargaJuego(tipoJuego *juego, FILE *arch);


int
main(void)
{
  int ret;
  char * nombre;
  tipoJuego juego;

  srand(time(NULL));
  
  while(1)
  {

	juego.parametros.opcion=menu();

	if(juego.parametros.opcion==TERMINAR)
		return;
  
	if(juego.parametros.opcion == MODO_NORMAL || juego.parametros.opcion == MODO_TIEMPO || juego.parametros.opcion == MODO_DOSJ)
	{
		ret=creaTablero(&juego);
		
		if(ret == NO_MEM)
			return;
		llenaTablero(&juego);
	}

	if(juego.parametros.opcion==CARGAR)
	{ 
		do
		{
			nombre=pideNombre();
			if(nombre == NULL)
				return;
			ret=load(&juego, nombre);
			free(nombre);
		}
		while(ret==FILE_ERROR);
	}
	else
		juego.turno=JUGADOR_1;

	if(juego.parametros.opcion == MODO_NORMAL || juego.parametros.opcion == MODO_TIEMPO || juego.parametros.opcion == MODO_DOSJ)
	{	
		
		ret=juegoF(&juego);
		if(ret==QUIT_CD)
		return;
	}

  	quit(&juego);

  }

}

int
cargaJuego(tipoJuego *juego, FILE *arch)
{
	int i,j;
	int ret;

	ret=fread(&(juego->parametros.opcion), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;
	juego->parametros.opcion+=1;
	if(juego->parametros.opcion==MODO_TIEMPO)
	{
		ret=fread(&(juego->tiempo), sizeof(int), 1, arch);
		if(ret!=1)
			return FILE_ERROR;
	}
	
	if(juego->parametros.opcion==MODO_DOSJ)
	{
		ret=fread(&(juego->turno),sizeof(int),1,arch);
		if(ret!=1)
			return FILE_ERROR;
	}

	ret=fread(&(juego->parametros.filas), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;
	ret=fread(&(juego->parametros.columnas), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;
	ret=fread(&(juego->parametros.colores), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;
	ret=fread(&(juego->parametros.linea), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;
	ret=fread(&(juego->parametros.bol_agregar), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;

	ret=creaTablero(&juego);
	if(ret==NO_MEM)
		return ret;

	ret=fread(&(juego->tablero1->puntaje), sizeof(int), 1, arch);
	if(ret!=1)
		return FILE_ERROR;

	for(i=0; i< juego->parametros.filas; i++)
		for(j=0; j< juego->parametros.columnas; j++)
			juego->tablero1->matriz[i][j]=fgetc(arch)-'0';

	if(juego->parametros.opcion==MODO_DOSJ)
	{
		fread(&(juego->tablero2->puntaje), sizeof(int), 1, arch);
		for(i=0; i< juego->parametros.filas; i++)
			for(j=0; j< juego->parametros.columnas; j++)
				juego->tablero2->matriz[i][j]=fgetc(arch)-'0';
	}

	return LOAD_CD;
}


int
load(tipoJuego *juego, char *nombre)
{
	FILE* archM;
	int ret;
	char * dir=malloc(strlen("./save/")+strlen(nombre)+1);

	if(dir == NULL)
	{
		printf("No hay memoria suficiente para cargar el juego\n");
		return NO_MEM;
	}

	strcpy(dir, "./save/");
	strcpy(dir+7, nombre);

	archM=fopen(dir, "r");
	if(archM==NULL)
	{
		printf("No se pudo cargar el juego\n");
		return FILE_ERROR;
	}
	else
	{
		ret=cargaJuego(juego, archM);
		if(ret==NO_MEM)
		{
			printf("No hay memoria suficiente para cargar el juego\n");
			return ret;
		}
		if(ret==FILE_ERROR)
		{
			printf("Problemas al cargar el juego\n");
			return ret;
		}
	}

	free(dir);
	fclose(archM);

	return ret;
}

int
save(tipoJuego* juego, char *nombre)
{
	FILE * archM;
	int ret;
	char * dir=malloc(strlen("./save/")+strlen(nombre)+1);

	if(dir == NULL)
	{
		printf("No hay memoria suficiente para guardar el juego\n");
		return NO_MEM;
	}

	while(*nombre == ' ')
		nombre++;
	if(*nombre == 0)
	{
		printf("Ingrese un nombre para el archivo\n");
		return FILE_ERROR;
	}
	else
	{
		strcpy(dir, "./save/");
		strcpy(dir+7, nombre);

		archM=fopen(dir, "w");
		if(archM==NULL)
		{
			printf("No se pudo guardar el juego\n");
			return FILE_ERROR;
		}
		else
		{
			guardaUndo(juego);
			guardaJuego(juego, archM);
		}
		fclose(archM);
	}

	free(dir);
	return SAVE_CD;
}

int randInt(int inicio, int final)
{
	return ((rand()/(double)RAND_MAX)*(final-inicio))+inicio;
}
int
creaTablero(tipoJuego *juego)
{
        int ret;
	int i;
	int j;

	pideParam(&(juego->parametros));

	ret=pideMem(&(juego->tablero1),juego->parametros);
	if(ret==NO_ERROR)
	{	
		juego->tablero1->cols=juego->parametros.columnas;
        	juego->tablero1->fils=juego->parametros.filas;
	}

	if(juego->parametros.opcion==MODO_DOSJ)
	{
		ret=pideMem(&(juego->tablero2), juego->parametros);
		if(ret==NO_ERROR)
		{
			juego->tablero2->cols=juego->parametros.columnas;
        		juego->tablero2->fils=juego->parametros.filas;
		}
	}

	else if(juego->parametros.opcion == MODO_NORMAL || juego->parametros.opcion == MODO_TIEMPO)
	{
	      	ret=pideMem(&(juego->tableroUndo), juego->parametros);
		if(ret==NO_ERROR)
		{
			juego->tableroUndo->cols=juego->parametros.columnas;
        		juego->tableroUndo->fils=juego->parametros.filas;
		}

	}


	if(ret==NO_MEM)
		printf("No hay suficiente memoria para correr el juego\n");

        return ret;
}
/* Recibe un puntero a tipoJuego y llena el tablero1 y si es necesario el tablero2 con ceros y con bol_inicial */
void
llenaTablero(tipoJuego *juego)
{
	int color;
	int i,j,k;

	for(i = 0; i < juego->parametros.filas; i++)
		for(j = 0; j < juego->parametros.columnas; j++)
		{
			juego->tablero1->matriz[i][j] = 0;
			if(juego->parametros.opcion == MODO_DOSJ)
				juego->tablero2->matriz[i][j] = 0;
		}

	for(k = 0; k < juego->parametros.bol_inicial; k++)
	{
		color = randInt(1, juego->parametros.colores);
		
		do{
			i = randInt(0, (juego->parametros.filas)-1);
			j = randInt(0, (juego->parametros.columnas)-1);
		}while(juego->tablero1->matriz[i][j] != 0);		/* Sigo buscando hasta encontrar un lugar vacio */

		juego->tablero1->matriz[i][j] = color;
		if(juego->parametros.opcion == MODO_DOSJ)
			juego->tablero2->matriz[i][j] = color;
	}

	juego->tablero1->puntaje = 0;

	if(juego->parametros.opcion == MODO_DOSJ)
		juego->tablero2->puntaje = 0;

	creaLibres(juego->tablero1, &((juego->tablero1)->puntos));
	if(juego->parametros.opcion == MODO_DOSJ)
		creaLibres(juego->tablero2, (&(juego->tablero2)->puntos));
	return;
}
int
juegoF(tipoJuego *juego)
{
	int ret;

	switch(juego->parametros.opcion)
	{
		case(MODO_NORMAL): ret=juegoNormal(juego); break;
		case(MODO_TIEMPO): ret=juegoTiempo(juego); break;
		case(MODO_DOSJ): ret=juegoVs(juego); break;
	}

	return ret;
}
int
menu()
{
	int opcion=0;

	putchar('\n');
	printf("Bienvenido a Colors\n");
	putchar('\n');
	printf("Ingrese la opcion de juego:\n");

	do{

	printf("\t(1) Juego de un jugador modalidad normal\n");
	printf("\t(2) Juego de un jugador modalidad por tiempo\n");
	printf("\t(3) Juego de dos jugadores en modalidad normal\n");
	printf("\t(4) Recuperar un juego grabado\n");
	printf("\t(5) Terminar\n");
	putchar('\n');

	opcion=getint("Opcion elegida: ");

	if(opcion<1 || opcion >5)
		printf("Opcion incorrecta, debe seleccionar una del menu:\n");

	}while(opcion<1 || opcion>5);

	return opcion;
}
char *
pideNombre(void)
{
        int i;
        int letra;
        char *entrada=NULL;
	char *aux = NULL;

	printf("Ingrese el nombre del archivo a cargar\n");

	for(i=0; (letra=getchar())!='\n' && letra!=EOF; i++)
	{
		if(i%BLOQUE==0)
		{
			aux=realloc(entrada, (i+BLOQUE)*sizeof(char));
			if(aux == NULL)
			{
				free(entrada);
				printf("No hay memoria suficiente para cargar el juego\n");
				return aux;
			}
			entrada = aux;
		}
				
		entrada[i]=letra;
	}
	entrada=realloc(entrada, (i+1)*sizeof(char));
	entrada[i]=0;

	return entrada;
}
int
juegoNormal(tipoJuego * juego)
{	
	int existe;
	int elim;
	int ret=AUX;
	int movida=0;
	int linea=juego->parametros.linea;
	int colores=juego->parametros.colores;
	guardaUndo(juego);
	imprimeTablero(juego);
	time_t tiempoIni=0;
	while( (ret != QUIT_CD) && ( !tableroLleno(juego->tablero1) ))	
	{	existe=elim=0;
		
		do
		{	ret=pideIn(juego, &movida, &elim, tiempoIni);
			if(ret == SIN_CAMINO)
				imprMsg(ret);
		}
		while((ret == SIN_CAMINO) || (ret==SIN_UNDO) || (ret == MAL_INGRESO) || (ret == INVALID_COOR));

		if(ret == NO_ERROR_C)
		{
			posibleElim(juego, &elim, linea, colores);

			if(elim == 0)
			{	bolitasAleat(juego);
				posibleElim(juego, &elim, linea, colores);
			}
			else
				sumaPuntaje(juego, elim);
		
			imprimeTablero(juego);
		}
		
	}

	if(ret!=QUIT_CD)
	{
		printf("Juego terminado. Resultados:\n");
		imprimeTablero(juego);
	}

	return ret;
}
int
juegoTiempo(tipoJuego * juego)
{	
	int existe;
	int elim;
	int ret=AUX;
	int movida=0;
	int segRest;
	int linea=juego->parametros.linea;
	int colores=juego->parametros.colores;
	juego->tiempo=pideTiempo();
	guardaUndo(juego);
	imprimeTablero(juego);
	time_t tiempoIni=time(NULL);
	

	while( (ret != QUIT_CD) && ( !tableroLleno(juego->tablero1)) && ( (hayTiempo(juego, tiempoIni)) > 0) && (ret!= NO_TIEMPO))	
	{	existe=elim=0;
		
		do
		{	ret=pideIn(juego, &movida, &elim, tiempoIni);
			if(ret == SIN_CAMINO)
				imprMsg(ret);
		}
		while((ret == SIN_CAMINO) || (ret==SIN_UNDO) || (ret == MAL_INGRESO) || (ret == INVALID_COOR) );

		if(ret == NO_ERROR_C)
		{
			posibleElim(juego, &elim, linea, colores);

			if(elim == 0)
			{	bolitasAleat(juego);
				posibleElim(juego, &elim, linea, colores);
			}
			else
				sumaPuntaje(juego, elim);
			
			imprimeTablero(juego);
			imprimeTiempo(juego);
		}
		
	}
	if(ret!=QUIT_CD)
	{	if( juego->tiempo <= 0)
			printf("Se acabo el tiempo.\n ");
		printf("Juego terminado. Resultados:\n");
		imprimeTablero(juego);
	}

	return ret;
}
int
pideTiempo()
{
	time_t tiempo;

	printf("Ingrese tiempo en minutos:\n");
	tiempo=getint("Tiempo elegido: ");
	
	while(tiempo<=0)
	{
		printf("El tiempo debe ser positivo, ingrese nuevamente:\n");
		tiempo=getint("Tiempo elegido: ");
	}
	return tiempo*60;
}
int
hayTiempo(tipoJuego * juego, time_t tiempoIni)
{
	time_t actual = time(NULL);
	juego->tiempo-= difftime(actual, tiempoIni);

		return juego->tiempo;
}
void
imprimeTiempo(tipoJuego * juego)
{	
	printf("Restan %d minutos y %d segundos.\n", juego->tiempo/60, juego->tiempo%60);

	return;
}

int
cargaUndo(tipoJuego * juego)
{	
 
	return copiaTablero(juego->tableroUndo, juego->tablero1);

}

int
copiaTablero(tipoTablero *origen, tipoTablero *destino)
{
	int i,j;
	tipoPunto *aux = NULL;

	aux = realloc(destino->puntos,(origen->dim_libres)*sizeof(tipoPunto));
	if(aux == NULL)
	{
		free(destino->puntos);
		return NO_MEM;
	}
	destino->puntos = aux;

	destino->fils = origen->fils;
	destino->cols = origen->cols;
	destino->puntaje = origen->puntaje;
	destino->dim_libres = origen->dim_libres;

	for(i = 0; i < destino->dim_libres; i++)
		destino->puntos[i] = origen->puntos[i];
	
	for(i=0; i < origen->fils; i++)
		for(j=0; j < origen->cols; j++)
			destino->matriz[i][j] = origen->matriz[i][j];

	return UNDO_CD;
}

int
guardaUndo(tipoJuego * juego)
{

	return copiaTablero(juego->tablero1, juego->tableroUndo);
	
 
}

int
juegoVs(tipoJuego * juego)
{	
	int existe;
	int elim, ganador;
	int ret=AUX;
	int movida=0;
	int linea=juego->parametros.linea;
	int colores=juego->parametros.colores;
	time_t tiempoIni=0;
	
	imprimeTablero(juego);
	
	while( (ret != QUIT_CD) && ( !tableroLleno(juego->tablero1) && !tableroLleno(juego->tablero1) ))	
	{	existe=elim=0;

		do
			ret=pideIn(juego, &movida, &elim, tiempoIni);
		while((ret == SIN_CAMINO) || (ret==SIN_UNDO) || (ret == MAL_INGRESO) || (ret == INVALID_COOR));

		if(ret == NO_ERROR_C)
		{
			posibleElim(juego, &elim, linea, colores);

			if(elim == 0)
			{	bolitasAleat(juego);
				posibleElim(juego, &elim, linea, colores);
			}
			else
				sumaPuntaje(juego, elim);
		
			imprimeTablero(juego);
		}
		cambiaTurno(juego);
	}

	if(ret!=QUIT_CD)
	{
		printf("Juego terminado. Resultados:\n");
		imprimeTablero(juego);
		if((juego->tablero1->puntaje) > (juego->tablero2->puntaje))
			printf("El ganador es el jugador 1!\n");
		else if((juego->tablero1->puntaje) < (juego->tablero2->puntaje))
			printf("El ganador es el jugador 2!\n");
		else
			printf("Hubo un empate!\n");
	}

	return ret;
}
void
cambiaTurno(tipoJuego * juego)
{
	if(juego->turno == JUGADOR_1)
		juego->turno=JUGADOR_2;
	else
		juego->turno=JUGADOR_1;
}

void
sumaPuntaje(tipoJuego *juego,int eliminados)
{
	int puntaje;

	if(eliminados == 0)
		puntaje = 0;

	else if(eliminados == juego->parametros.linea)
		puntaje = MIN;

	else if(eliminados == (juego->parametros.linea)+1)
		puntaje = MAS_UNA;

	else if(eliminados == (juego->parametros.linea)+2)
		puntaje = MAS_DOS;

	else if(eliminados == (juego->parametros.linea)+3)
		puntaje = MAS_TRES;

	else if(eliminados > (juego->parametros.linea)+3)
		puntaje = MAS_DE_TRES;

	if(juego->turno == JUGADOR_1)
		juego->tablero1->puntaje += puntaje;

	else if(juego->turno == JUGADOR_2)
		juego->tablero2->puntaje += puntaje;

}

void
imprimeTablero(tipoJuego *juego)
{
	int i,j;
	
	printf("      ");
	for(i = 0; i < juego->parametros.columnas; i++)
		printf(" %-2d ",i);

	if(juego->parametros.opcion == MODO_DOSJ)
	{
		printf("\t|\t");
		printf("      ");
		for(i = 0; i < juego->parametros.columnas; i++)
			printf(" %-2d ",i);
	}

	putchar('\n');

	for(i=0; i < juego->parametros.filas; i++)
        {
		putchar('\n');
		printf(" %3d  ", i);
		for(j=0; j < juego->parametros.columnas; j++)
			imprimeFila(juego->tablero1, i, j);
		
		if(juego->parametros.opcion == MODO_DOSJ)
		{
			printf("\t|\t");
			printf(" %3d  ", i);
			for(j=0; j < juego->parametros.columnas; j++)
				imprimeFila(juego->tablero2, i, j);
		}

	}
	putchar('\n');
	putchar('\n');
	
	imprimePuntaje(juego,1);

	if(juego->parametros.opcion == MODO_DOSJ)
	{
		for(i = 0; i < (juego->parametros.columnas) - 5; i++)
			printf("    ");
		printf("\t\t|\t");
		imprimePuntaje(juego,2);
	}
	printf("\n");

}

void imprimeFila(tipoTablero *tablero, int i, int j)
{
	switch(tablero->matriz[i][j])
	{
		case 1: printf(" A  "); /* Azul */
			break;
		case 2: printf(" R  "); /* Rojo */
			break;
		case 3: printf(" V  "); /* Verde */
			break;
		case 4: printf(" N  "); /* Naranja */
			break;
		case 5: printf(" P  "); /* Purpura */
			break;
		case 6: printf(" C  "); /* Celeste */
			break;
		case 7: printf(" B  "); /* Blanco */
			break;
		case 8: printf(" G  "); /* Gris */
			break;
		case 9: printf(" F  "); /* Fucsia */
			break;
		case 0: printf(" .  "); /* Fucsia */
			break;
		default: printf(" *  "); /* Negro */ /* Vacio (matriz[i][j] == 0) */
			break;
	}
}

/* Recibe una estructura juego, y el numero del judador del que se quiere imprimir el puntaje */

void
imprimePuntaje(tipoJuego *juego, int jugador)
{
	switch(jugador){
		case 1: printf("Puntaje Jugador1: %d",juego->tablero1->puntaje);
			break;
		case 2:	printf("Puntaje Jugador2: %d",juego->tablero2->puntaje);
			break;
	}

	return;
}

int
tableroLleno(tipoTablero * tablero)
{
	return (tablero->dim_libres == 0) ;
}

int
pideIn(tipoJuego *juego, int *movida, int *elim,time_t tiempoIni)
{
        int i;
        int letra;
	int ret;
	char *entrada=NULL;
	char *aux=NULL;
	int segRest;
	
	
	printf("Jugador %d ingrese la accion a realizar\n", juego->turno);

	for(i=0; (letra=getchar())!='\n' && letra!=EOF; i++)
	{
		if(i%10==0)
			aux=realloc(entrada, (i+10)*sizeof(char));
		if(aux==NULL)
		{
			free(entrada);
			return NO_MEM;
		}
		entrada=aux;
		entrada[i]=letra;
	}
	entrada=realloc(entrada, (i+1)*sizeof(char));
	entrada[i]=0;
	if(juego->parametros.opcion==2)
		if(hayTiempo(juego, tiempoIni)<=0)
		{	ret=NO_TIEMPO;
			return ret;
		}	
	ret=validaIn(juego, entrada, movida, elim);
			imprMsg(ret);
	return ret;
}
void
imprMsg(int var)
{
	if(var==INVALID_COOR)
	{
		printf("Coordenadas no validas\n");
		printf("Ingrese nuevamente\n");
	}
	else if(var==MAL_INGRESO)
	{
		printf("Opcion inexistente o con errores\n");
		printf("por favor ingrese nuevamente\n");
	}
	else if(var==FILE_ERROR)
	{
		printf("Problema para guardar\n");
		printf("Ingrese otro comando o archivo\n");
	}
	else if(var==QUIT_CD)
		printf("Gracias por jugar\n");
	else if(var==UNDO_CD)
	{
		printf("Undo aceptado\n");
		printf("Puede continuar\n");
	}
	else if(var==SAVE_CD)
	{
		printf("Juego guardado\n");
		printf("Puede continuar\n");
	}
	else if(var==NO_ERROR_C)
		printf("Cambio hecho\n");
	else if(var==MOV_DUPL)
		printf("No se puede realizar mas de un movimiento por turno\n");
	else if(var==DOS_UNDO)
		printf("Solo se puede realizar un Undo luego de una movida\n");
	else if(var==SIN_CAMINO)
		printf("No existe un camino\n");
}
int
quit(tipoJuego *juego)
{
        if(juego->parametros.opcion==3)
        	quitTablero(&juego->tablero2);
        
	else
		quitTablero(&juego->tableroUndo);
	quitTablero(&juego->tablero1);

	return QUIT_CD;
}

void
quitTablero(tipoTablero **tablero)
{
	int i;

        for(i=0; i<(*tablero)->fils; i++)
                free((*tablero)->matriz[i]);
        free((*tablero)->matriz);
        free(*tablero);
}
int
validaIn(tipoJuego * juego, char *s, int *movida, int *elim)
{

	int ret;
	int coord[4];
	int opcion;
	tipoPunto punto1, punto2;

	opcion = juego->parametros.opcion;

	if(strcmp(s, "quit")==0)
		ret=quit(juego);
	else if(strncmp(s, "save ", 5)==0)
		/*ret=save(juego, s+5)*/;
	else if(strcmp(s, "undo")==0)
	{	if(opcion != 3)
		{	if(*movida!=0)
			{	ret=cargaUndo(juego);
				*movida=0;
				imprimeTablero(juego);
			}
			else ret=DOS_UNDO;
		}
		else ret=SIN_UNDO;
	}
	else if(s[0]=='[' && validMov(juego->parametros, s, coord))
	{
		punto1.x=coord[0];
		punto1.y=coord[1];
		punto2.x=coord[2];
		punto2.y=coord[3];
		
		if(CoordValidas(juego, punto1, punto2))
		{	if(opcion != 3)
				guardaUndo(juego);
			ret=posibleMov(juego, punto1, punto2, movida);

			if(ret==NO_ERROR_C)
				*movida=1;
			else if(ret == SIN_CAMINO)
				  ret=SIN_CAMINO;
		}
		else
			ret=INVALID_COOR;
				
	}
	else
		ret=MAL_INGRESO;

	free(s);

	return ret;
}

int
validMov(tipoParametros param, char *s, int vec[])
{
	int num1, num2, num3, num4;
	int v1, v2, v3, v4;
	sscanf(s, "[%d,%d]->[%d,%d]", &num1, &num2, &num3, &num4);

	vec[0]=num1;
	vec[1]=num2;
	vec[2]=num3;
	vec[3]=num4;	
	
	v1=(num1>=0 && num1<param.filas);
	v2=(num2>=0 && num2<param.columnas);
	v3=(num3>=0 && num3<param.filas);
	v4=(num4>=0 && num4<param.columnas);
		
	return v1 && v2 && v3 && v4;
	
}

int
posibleElim(tipoJuego * juego, int *elim, int linea, int cantColores)
{
	tipoTablero * tablero;
	int i, j, c;
	int limitei, limitej;
	
	if(juego->turno==JUGADOR_1)
		tablero=juego->tablero1;
	else
		tablero=juego->tablero2;
	
	limitei= tablero->fils-linea+1;
	limitej= tablero->cols-linea+1;


	for(c=1; c <= cantColores; c++)
	{	
	  	for(i=0; i < (tablero->fils); i++)
			for(j=0; j< limitej; j++)
				if((tablero->matriz[i][j] == c) || (tablero->matriz[i][j] == -1))
					elimHor(tablero, i, &j, elim, linea, c);
					
		for(i=0; i <= limitei; i++)
			for(j=0; j< (tablero->cols); j++)
				if((tablero->matriz[i][j] == c) || (tablero->matriz[i][j] == -1))
					elimVer(tablero, i, j, elim, linea, c);			

		for(i=0; i <= limitei; i++)
			for(j=0; j<= limitej; j++)

				if((tablero->matriz[i][j] == c) || (tablero->matriz[i][j] == -1))
				{	elimDiag(tablero, i, j, elim, linea, c, IZQ);
					elimDiag(tablero, i, j, elim, linea, c, DER);
				}
		
					
	ceros(tablero);
	
	}
	
	
	return 0;
}
int
elimHor(tipoTablero * tablero, int i, int *j, int * elim, int linea, int color)
{	int cantH;
	int auxj=*j;

	cantH=cuentaHor(tablero, color,  i, auxj);

	if(cantH >= linea)
	{	while(cantH--)
		{	if(tablero->matriz[i][auxj]==color)
			{	(*elim)++;

				tablero->matriz[i][auxj]=-1;
			}
			auxj++;
		}
		*j=auxj;
	}
	return 0;
}
int
elimVer(tipoTablero * tablero, int i, int j, int * elim, int linea, int color)
{	int cantV;
	int auxi=i;
	
	
	cantV=cuentaVer(tablero, color,  auxi, j);

	if(cantV >= linea)
	{	while(cantV--)
		{	if(tablero->matriz[auxi][j]== color)
			{	(*elim)++;

				tablero->matriz[auxi][j]=-1;
			}
			auxi++;
		}
		i=auxi;
	}
	return 0;
}
int
elimDiag(tipoTablero * tablero, int i, int j, int * elim, int linea, int color, int orient)
{	int cantD;
	
	cantD=cuentaDiag(tablero, color,  i, j, orient);

	if(cantD >= linea)
	{	while(cantD--)
		{	if(tablero->matriz[i][j]== color)	
			{	(*elim)++;
				tablero->matriz[i][j]=-1;
			}
			i++;
			j= ((orient==IZQ)? j-1 : j+1);
		}
		
	}
	return 0;
}
int
cuentaHor(tipoTablero * tablero, int color, int i, int j)
{	 
	if( (tablero->matriz[i][j]==color) || (tablero->matriz[i][j]== -1))
		if(j+1 < tablero->cols)
			return 1+ cuentaHor(tablero, color, i, j+1);
		else
			return 1;
	return 0;
}
int
cuentaVer(tipoTablero * tablero, int color, int i, int j)
{
	if( (tablero->matriz[i][j]==color) || (tablero->matriz[i][j]== -1) ) 
		if(i+1 < tablero->fils)
			return 1+ cuentaVer(tablero, color, i+1, j);
		else
			return 1;
	return 0;
}	
int
cuentaDiag(tipoTablero * tablero, int color, int i, int j, int orient)
{
	if( (tablero->matriz[i][j]==color) || (tablero->matriz[i][j]== -1)) 
	{	j= ((orient==IZQ)? j-1 : j+1);
		if((i+1 < tablero->fils) && (j < tablero->cols) && (j >= 0))
			return 1+ cuentaDiag(tablero, color, i+1, j, orient);
		else
			return 1;
	}
	return 0;
}
int
ceros(tipoTablero * tablero)
{	int i, j;
  
	  for(i=0; i < tablero->fils; i++)
		for(j=0; j < tablero->cols; j++)
			if(tablero->matriz[i][j]==-1)
			
			  tablero->matriz[i][j]=0;
	  return 0;
}


void
tomaMov(tipoPunto *origen, tipoPunto *destino)
{
	origen->x=getint("Ingrese la coord x de origen:\n");
	origen->y=getint("Ingrese la coord y de origen:\n");
	destino->x=getint("Ingrese la coord x de destino:\n");
	destino->y=getint("Ingrese la coord y de destino:\n");
}

int
posibleMov(tipoJuego * juego, tipoPunto origen, tipoPunto destino, int *existe)
{	int colorAux;
	tipoTablero * tablero;

	*existe=0;
	if(juego->turno==JUGADOR_1)
		tablero=juego->tablero1;
	else
		tablero=juego->tablero2;

	colorAux=tablero->matriz[origen.x][origen.y];
	tablero->matriz[origen.x][origen.y]=0;
	
	posCamino(tablero, origen, destino, existe);
	
	tablero->matriz[origen.x][origen.y]=colorAux;
	
	if(*existe == 1)
	{	swap(tablero, origen, destino);
		ceros(tablero);
		return NO_ERROR_C;
		
	}
	ceros(tablero);
	return SIN_CAMINO;
}
	

int 
posCamino(tipoTablero * tablero, tipoPunto origen, tipoPunto destino, int *existe)
{	
	tipoPunto punto;


	if( (origen.x == destino.x) && (origen.y == destino.y) )
	{	*existe=1;

		return 0;
	}

	if((tablero->matriz[origen.x][origen.y] == 0) && (*existe == 0))
	{	tablero->matriz[origen.x][origen.y] = -1;
	  
		punto.x=(origen.x)+1;
		punto.y=(origen.y);
		if(pertenMat(tablero, punto))
			posCamino(tablero, punto, destino, existe);
		
		punto.x=(origen.x);
		punto.y=(origen.y)+1;
		if(pertenMat(tablero, punto))
			posCamino(tablero, punto, destino, existe);
		
		punto.x=(origen.x)-1;
		punto.y=(origen.y);
		if(pertenMat(tablero, punto))
			posCamino(tablero, punto, destino, existe);
	
		punto.x=(origen.x);
		punto.y=(origen.y)-1;
		if(pertenMat(tablero, punto))
			posCamino(tablero, punto, destino, existe);
	
	}	
	return 0;

}
		
int 
CoordValidas(tipoJuego *juego, tipoPunto origen, tipoPunto destino)
{	tipoTablero * tablero;
	if(juego->turno==JUGADOR_1)
		tablero=juego->tablero1;
	else
		tablero=juego->tablero2;
	int dentro, origValido, destValido;
	dentro=(pertenMat(tablero, origen) && pertenMat(tablero, destino));
	origValido=( (tablero->matriz[origen.x][origen.y]) != 0 );
	destValido=( (tablero->matriz[destino.x][destino.y]) == 0 );
	
	return (dentro && origValido && destValido);
}
		
int
pertenMat(tipoTablero * tablero, tipoPunto punto)
{
	int v1, v2;

	v1= (punto.x>=0) && (punto.x<tablero->fils);
	v2= (punto.y>=0) && (punto.y<tablero->cols);

	return v1 && v2;
}


int
swap(tipoTablero * tablero, tipoPunto origen, tipoPunto destino)
{
	tablero->matriz[destino.x][destino.y]=tablero->matriz[origen.x][origen.y];
	tablero->matriz[origen.x][origen.y]=0;
	actualizaLibresM(tablero, origen, destino);
	
	return 0;
}

void
actualizaLibresM(tipoTablero * tablero, tipoPunto coordIni, tipoPunto coordFin)
{
	int i;
  
	for(i=0;i<tablero->dim_libres;i++)
		if(tablero->puntos[i].x == coordFin.x && tablero->puntos[i].y==coordFin.y)
		{       tablero->puntos[i].x = coordIni.x;
			tablero->puntos[i].y = coordIni.y;
		}
  
}



void
bolitasAleat(tipoJuego *juego)
{
	tipoTablero *tablero;
	
	if(juego->turno==JUGADOR_1)
		tablero=juego->tablero1;
	else if(juego->turno==JUGADOR_2)
		tablero=juego->tablero2;	
		
	int i, j, k, l, m=0;
	for(i=0;i<juego->parametros.bol_agregar;i++)	
	{
		j=rand()%(juego->parametros.colores)+1; 
		k=rand()%((tablero)->dim_libres-m);
		agrega_bolita(tablero, j,(tablero)->puntos[k].x,(tablero)->puntos[k].y);
		copiaEstruct(&(tablero)->puntos[k],&(tablero)->puntos[tablero->dim_libres-m-1]);
		m++;
	}
	(tablero)->dim_libres-=m;
	tablero->puntos=realloc(tablero->puntos, sizeof(tipoPunto)*(tablero->dim_libres));
	
}

void
agrega_bolita(tipoTablero *tablero, int r, int  i, int j)
{
	tablero->matriz[i][j]=r;

}
/*copia tipoPunto b , a tipoPunto a*/
void
copiaEstruct(tipoPunto *a, tipoPunto * b)
{
	*a=*b;
}
int
creaLibres(tipoTablero *tablero, tipoPunto **puntos)
{
	int i, j, k=0;
	*puntos=NULL;
	tipoPunto *aux;

	for(i=0;i<tablero->fils;i++)
		for(j=0;j<tablero->cols;j++)
		{
			if(k%10==0)
			{	aux=*puntos;
				aux=realloc(aux, sizeof(tipoPunto)*(k+10));
				if(aux==NULL)
				{	free(*puntos);
					return NO_MEM;
				}
				else
				{
					*puntos=aux;
				}
			}
			if(tablero->matriz[i][j]==0)
			{
				(*puntos)[k].x=i;
				(*puntos)[k++].y=j;	
			}
			
		}
	tablero->dim_libres=k;
	*puntos=realloc(*puntos, sizeof(tipoPunto)*k);
}


void
pideParam(tipoParametros *parametros)
{
  do{
      parametros->filas=getint("Ingrese la cantidad de filas del tablero (minimo 5, maximo 15):\n");
      if(parametros->filas<MIN_DIM || parametros->filas>MAX_DIM)
	printf("Opcion incorrecta, debe seleccionar un numero de filas entre 5 y 15\n");
  }while(parametros->filas<MIN_DIM || parametros->filas>MAX_DIM);
  
  do{
      parametros->columnas=getint("Ingrese la cantidad de columnas del tablero (minimo 5, maximo 15):\n");
       if(parametros->columnas<MIN_DIM || parametros->columnas>MAX_DIM)
	printf("Opcion incorrecta, debe seleccionar un numero de columnas entre 5 y 15\n");
  }while(parametros->columnas<MIN_DIM || parametros->columnas>MAX_DIM);
  
  do{
      parametros->colores=getint("Ingrese la cantidad de colores con los que quiere jugar (minimo 2, maximo 9):\n");
      if(parametros->colores<MIN_COLOR || parametros->colores>MAX_COLOR)
	printf("Opcion incorrecta, debe ingresar un numero de colores entre 2 y 9\n");
  }while(parametros->colores<MIN_COLOR || parametros->colores>MAX_COLOR); 
  
  do{
	parametros->bol_inicial=getint("Ingrese la cantidad de bolillas iniciales (minimo 2, maximo 9):\n");
	if(parametros->bol_inicial<MIN_BOL_INI || parametros->bol_inicial>MAX_BOL_INI)
	printf("Opcion incorrecta, debe ingresar un numero de bolillas iniciales entre 2 y 9\n"); 
  }while(parametros->bol_inicial<MIN_BOL_INI || parametros->bol_inicial>MAX_BOL_INI); 
  
  do{
      parametros->linea=getint("Ingrese la cantidad de bolillas que forman una linea (minimo 3):\n");
      if(parametros->linea<MIN_LINEA || parametros->linea>parametros->filas || parametros->linea>parametros->columnas)
	printf("Opcion incorrecta, debe ingresar el numero de bolillas que conforman una linea con un numero entre 3 y que sea menor al numero de filas y columnas\n"); 
  }while(parametros->linea<MIN_LINEA || parametros->linea>parametros->filas || parametros->linea>parametros->columnas);
  
  do{
	parametros->bol_agregar=getint("Ingrese la cantidad de bolillas a agregar en cada turno (minimo 2, maximo 9):\n");
	 if(parametros->bol_agregar<MIN_TURNO || parametros->bol_agregar>MAX_TURNO)
	printf("Opcion incorrecta, ingrese un numero de bolillas a agregar entre 2 y 9\n"); 
  }while(parametros->bol_agregar<MIN_TURNO || parametros->bol_agregar>MAX_TURNO);
}


int 
pideMem(tipoTablero **tablero, tipoParametros parametros)
{
	int i,j;

	*tablero = malloc(sizeof(tipoTablero));
	if(*tablero == NULL)
		return NO_MEM;

	(*tablero)->matriz = malloc((parametros.filas)*sizeof(int*));
	if((*tablero)->matriz == NULL)
	{
		free(*tablero);
		return NO_MEM;
	}

	for(i = 0; i < parametros.filas; i++)
	{
		(*tablero)->matriz[i] = malloc((parametros.columnas)*sizeof(int));
		if((*tablero)->matriz[i] == NULL)
		{
			for(j = 0; j < i; j++)
				free((*tablero)->matriz[j]);
			free((*tablero)->matriz);
			free(*tablero);
			return NO_MEM;
		}
	}
		return NO_ERROR;
}
void
inicialTablero(tipoTablero *tablero, tipoParametros param)
{
  int i, j, k, l;
  
  for(i=0; i<param.bol_inicial;i++)
  {
    j=(rand()%param.colores)+1;
    k=(rand()%param.filas-1)+1;
    l=(rand()%param.columnas-1)+1;    
    tablero->matriz[k][l]=j;
  }

}

